package hasthi.tools;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.Arrays;
import java.util.Properties;

import hasthi.common.*;
import hasthi.common.constants.HasthiConstants;
import hasthi.container.MessageContext;
import hasthi.container.SimpleMessageContext;
import hasthi.container.XsulBasedSoapContainer;
import hasthi.manager.GetCoordinatorDocument;
import hasthi.manager.GetCoordinatorResponseDocument;
import hasthi.manager.ManagerAddress;
import hasthi.manager.NotifyEventDocument;
import hasthi.manager.ResolveServiceDependancyByTypeDocument;
import hasthi.manager.ResolveServiceDependancyByTypeResponseDocument;
import hasthi.manager.SuspectFaultyDocument;
import hasthi.manager.NotifyEventDocument.NotifyEvent;
import hasthi.manager.ResolveServiceDependancyByTypeDocument.ResolveServiceDependancyByType;
import hasthi.manager.ResolveServiceDependancyByTypeResponseDocument.ResolveServiceDependancyByTypeResponse.ServiceData;
import hasthi.manager.SuspectFaultyDocument.SuspectFaulty;

import javax.xml.namespace.QName;

import org.apache.xmlbeans.XmlObject;

import xsul.invoker.http.HttpDynamicInfosetInvoker;

public class HasthiClient {
    private XsulBasedSoapContainer container;
    private String bootstrapNodeUrl;
    private String coordinatorUrl;

    public HasthiClient(String bootstrapNodeUrl,XsulBasedSoapContainer container) throws HasthiException {
        this.container = container;
        this.bootstrapNodeUrl = bootstrapNodeUrl;
    }
    
    public HasthiClient(String bootstrapNodeUrl) throws HasthiException {
        try {
            Properties properties = new Properties();
            properties.setProperty(HasthiOptions.BOOTSTRAP_NODE, new URL(bootstrapNodeUrl).getHost());
            BaseContext baseContext = new BaseContext(properties);
            container = (XsulBasedSoapContainer) ComponetFactory
                    .createSoapContianier(baseContext, null);
            this.bootstrapNodeUrl = bootstrapNodeUrl;
        } catch (MalformedURLException e) {
            throw new HasthiException(e,HasthiException.FaultCode.InvaliedLocalArgumnet);
        }
    }

    public HasthiClient(BaseContext baseContext) throws HasthiException {
            container = (XsulBasedSoapContainer) ComponetFactory
                    .createSoapContianier(baseContext, null);
            this.bootstrapNodeUrl = new StringBuffer().append("http://")
                .append(baseContext.getBoostrapHost()).append(":")
                .append(baseContext.getBoostrapSoapPort()).append("/").toString();
    }

    
    public ServiceData[] lookupAServiceInstances(QName[] servicePortTypeNames) throws HasthiException {
        if(coordinatorUrl == null){
            coordinatorUrl = getCoordinator(bootstrapNodeUrl);
            if(coordinatorUrl == null){
                return null;
            }
        }
        ResolveServiceDependancyByTypeDocument document = ResolveServiceDependancyByTypeDocument.Factory.newInstance();
        ResolveServiceDependancyByType resolveServiceDependancyByType = document.addNewResolveServiceDependancyByType();
        
        resolveServiceDependancyByType.setPortTypeNameArray(servicePortTypeNames);
        
        SimpleMessageContext request = new SimpleMessageContext(document,coordinatorUrl,
                HasthiConstants.MANEGER_NS + HasthiConstants.RESOLVE_DEPENDANCY_LABEL);
        ResolveServiceDependancyByTypeResponseDocument response = (ResolveServiceDependancyByTypeResponseDocument)container.sendReceive(request);
        ServiceData[] serviceDataArray = response.getResolveServiceDependancyByTypeResponse().getServiceDataArray();
        
        return serviceDataArray;
    }
    
    public ServiceData lookupAServiceInstance(QName servicePortTypeName) throws HasthiException{
        ServiceData[] serviceDataArray = lookupAServiceInstances(new QName[]{servicePortTypeName});
        if(serviceDataArray != null && serviceDataArray.length > 0){
            return serviceDataArray[0];
        }
        return null;

    }
    
    public String notifyError(XmlObject errorMessage) throws HasthiException{
        if(coordinatorUrl == null){
            coordinatorUrl = getCoordinator(bootstrapNodeUrl);
            if(coordinatorUrl == null){
                return null;
            }
        }
        
        NotifyEventDocument notifyEventDocument = NotifyEventDocument.Factory.newInstance();
        NotifyEvent notifyEvent = notifyEventDocument.addNewNotifyEvent();
        notifyEvent.setContent(errorMessage);
        notifyEvent.setName(HasthiConstants.NOTIFY_ERROR);
        
        SimpleMessageContext request = new SimpleMessageContext(notifyEventDocument,coordinatorUrl,
                HasthiConstants.NOTIFY_ERROR_ACTION);
        container.send(request);
        return null;
    }
    
    
    public String notifyError(String errorMessage) throws HasthiException{
        if(coordinatorUrl == null){
            coordinatorUrl = getCoordinator(bootstrapNodeUrl);
            if(coordinatorUrl == null){
                return null;
            }
        }
        StringBuffer buffer = new StringBuffer();
        buffer.append(coordinatorUrl).append("/hasthi/").append(HasthiConstants.LABEL_TRIGGER_EVENT).append("/")
            .append(HasthiConstants.NOTIFY_ERROR).append("?").append(HasthiConstants.NOTIFY_ERROR_ERRORDESC)
            .append("=").append(errorMessage);
        
        String response = new HttpDynamicInfosetInvoker().invokeHttpGet(buffer.toString());
        return response;
    }
    
    public void sendSuspectFaulty(QName serviceName) throws HasthiException{
        if(coordinatorUrl == null){
            coordinatorUrl = getCoordinator(bootstrapNodeUrl);
            if(coordinatorUrl == null){
                return;
            }
        }
        SuspectFaultyDocument suspectFaultyDocument = SuspectFaultyDocument.Factory.newInstance();
        SuspectFaulty suspectFaulty = suspectFaultyDocument.addNewSuspectFaulty();
        suspectFaulty.setServiceName(serviceName);
        MessageContext message2 = new SimpleMessageContext(suspectFaultyDocument, coordinatorUrl,
                HasthiConstants.SUSPECT_FAULTY_ACTION);
        container.send(message2);
    }


    private String getCoordinator(String bootstrapNodeUrl) throws HasthiException {
        GetCoordinatorDocument coordinatorDocument = GetCoordinatorDocument.Factory.newInstance();
        coordinatorDocument.addNewGetCoordinator();
        MessageContext message2 = new SimpleMessageContext(coordinatorDocument, bootstrapNodeUrl,
                HasthiConstants.GET_COORDINATOR_ACTION);
        GetCoordinatorResponseDocument coordinatorResponse = (GetCoordinatorResponseDocument) container
                .sendReceive(message2);
        ManagerAddress managerAddress = coordinatorResponse.getGetCoordinatorResponse()
                .getAddress();
        if (managerAddress != null) {
            return managerAddress.getSoapAddress();
        }
        return null;
    }

    
    public static void main(String[] args) throws HasthiException {
        HasthiClient client = new HasthiClient("http://linbox3:9002");
        //HasthiClient client = new HasthiClient("http://linbox3:9002");
//        String[] concreateServiceInstances  = client.lookupAServiceInstances(new QName("Version"));
//        //String[] concreateServiceInstances  = client.lookupAServiceInstances(QName.valueOf("{http://extreme.indiana.edu/dummyservice/}DSC"));
//        
//        System.out.println(Arrays.toString(concreateServiceInstances));
//        System.out.println(client.notifyError("InternarlServerError"));
        
        client.sendSuspectFaulty(QName.valueOf("{http://extreme.indiana.edu/dummyService}Foo0"));
        
    }
}
